/**
 * This file is part of 1genia trampoline
 * Copyright (C) 2007 - 2008 1genia (contact@1genia.com)
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; version 3 of the License. 
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details. 
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; see the file COPYING.TXT.  If not,
 * write to the Free Software Foundation, Inc., 51 Franklin Street,
 * Fifth Floor, Boston, MA 02110-1301, USA. 
 **/
package com.genia.toolbox.form.editor.model.visitor;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.genia.toolbox.basics.exception.technical.TechnicalIOException;
import com.genia.toolbox.constants.client.Charset;
import com.genia.toolbox.web.gwt.basics.client.exception.GwtBundledException;
import com.genia.toolbox.web.gwt.basics.client.i18n.GwtI18nMessage;
import com.genia.toolbox.web.gwt.form.client.form.BasicForm;
import com.genia.toolbox.web.gwt.form.client.form.ButtonItem;
import com.genia.toolbox.web.gwt.form.client.form.CheckBoxItem;
import com.genia.toolbox.web.gwt.form.client.form.DateItem;
import com.genia.toolbox.web.gwt.form.client.form.DateTimeItem;
import com.genia.toolbox.web.gwt.form.client.form.DynamicListBoxItem;
import com.genia.toolbox.web.gwt.form.client.form.DynamicRadioButtonItem;
import com.genia.toolbox.web.gwt.form.client.form.EnumDescriptableValuedItemEntryList;
import com.genia.toolbox.web.gwt.form.client.form.FileUploadItem;
import com.genia.toolbox.web.gwt.form.client.form.Form;
import com.genia.toolbox.web.gwt.form.client.form.HorizontalForm;
import com.genia.toolbox.web.gwt.form.client.form.I18nTextAreaItem;
import com.genia.toolbox.web.gwt.form.client.form.I18nTextBoxItem;
import com.genia.toolbox.web.gwt.form.client.form.ImageItem;
import com.genia.toolbox.web.gwt.form.client.form.InlineFormItem;
import com.genia.toolbox.web.gwt.form.client.form.InlineFormMultipleItem;
import com.genia.toolbox.web.gwt.form.client.form.InlineFormSimpleItem;
import com.genia.toolbox.web.gwt.form.client.form.Item;
import com.genia.toolbox.web.gwt.form.client.form.LabelItem;
import com.genia.toolbox.web.gwt.form.client.form.LabeledForm;
import com.genia.toolbox.web.gwt.form.client.form.ListBoxItem;
import com.genia.toolbox.web.gwt.form.client.form.MultipleFileUploadItem;
import com.genia.toolbox.web.gwt.form.client.form.PasswordBoxItem;
import com.genia.toolbox.web.gwt.form.client.form.RadioButtonItem;
import com.genia.toolbox.web.gwt.form.client.form.RichTextAreaItem;
import com.genia.toolbox.web.gwt.form.client.form.SimpleItem;
import com.genia.toolbox.web.gwt.form.client.form.SimpleValuedItemEntryList;
import com.genia.toolbox.web.gwt.form.client.form.SubFormMultipleItem;
import com.genia.toolbox.web.gwt.form.client.form.SubFormSimpleItem;
import com.genia.toolbox.web.gwt.form.client.form.TabForm;
import com.genia.toolbox.web.gwt.form.client.form.TextAreaItem;
import com.genia.toolbox.web.gwt.form.client.form.TextBoxItem;
import com.genia.toolbox.web.gwt.form.client.form.TimeItem;
import com.genia.toolbox.web.gwt.form.client.form.ValuedItem;
import com.genia.toolbox.web.gwt.form.client.form.ValuedItemEntry;
import com.genia.toolbox.web.gwt.form.client.form.ValuedItemEntryList;
import com.genia.toolbox.web.gwt.form.client.form.VerticalForm;
import com.genia.toolbox.web.gwt.form.client.service.FormService;
import com.genia.toolbox.web.gwt.form.client.value.impl.DataIdentifierImpl;
import com.genia.toolbox.web.gwt.form.client.visitor.FormVisitor;

/**
 * this class generates jsp which represents a 1gtoolbox form understable by jsp
 * container.
 */
public class JspWriterFormVisitor
    implements FormVisitor
{

  /**
   * Logger for the class.
   */
  private static final Logger LOGGER = LoggerFactory.getLogger(JspWriterFormVisitor.class);

  /**
   * the {@link FormService} needed to retrieve the sub and inline forms.
   */
  private FormService formService;

  /**
   * Exception which occured during process, if any.
   */
  private Exception exception = null;

  /**
   * The parent item of the current visited item.
   */
  private Form parentItem;

  /**
   * the indent.
   */
  private int indent = 0;

  /**
   * the jsp pages directives.
   */
  private static Collection<String> pagesdirectives;

  /**
   * the jsp taglib directives.
   */
  private static Collection<String> taglibdirectives;

  /**
   * the jsp header .
   */
  private static String header;

  static {

    pagesdirectives = new ArrayList<String>(1);
    pagesdirectives.add("\n<%@ page language=\"java\" contentType=\"text/html; charset=" + Charset.UTF8 + "\" pageEncoding=\"" + Charset.UTF8 + "\"%>");

    taglibdirectives = new ArrayList<String>(4);
    taglibdirectives.add("\n<%@ taglib prefix=\"c\" uri=\"http://java.sun.com/jsp/jstl/core\"%>");
    taglibdirectives.add("\n<%@ taglib prefix=\"fmt\" uri=\"http://java.sun.com/jsp/jstl/fmt\"%>");
    taglibdirectives.add("\n<%@ taglib uri=\"http://jakarta.apache.org/taglibs/unstandard-1.0\" prefix=\"u\"%>");
    taglibdirectives.add("\n<%@ taglib uri=\"http://www.1genia.com/trampoline-basics-project\" prefix=\"tbp\"%>");

    header = new String();
    header = "  <style>   .tbpFlatForm div {\n  float: left;\n}\n\n.tbpFlatForm {\n     clear: both;\n}\n\n.itemLabel {\n       background-color: #EEEFFF;\n    margin-left: 15px;\n}\n\n.HorizontalFormImpl {\n        border: 1px #DDDDDD solid;\n    clear: both;\n  width: 700px;\n}\n\n.TabFormImpl {\n    border: 1px red solid;\n}\n\n.TabFormImpl div {\n       border: 1px red solid;\n}\n\n.TabFormImpl div div {\n   border: none\n}\n\n#tabs .hiddenTabContent {\n  display: none;\n}\n\n#tabs .showedTabContent {\n        display: block;\n}\n\n#tabs,#tabTitles {\n      clear: both;\n}\n\n#tabTitles .inactiveTab {\n  border: 2px black solid;\n      background-color: gray;\n}\n\n#tabTitles .activeTab {\n border: 2px black solid;\n      background-color: orange;\n}\n\n* .HorizontalFormImpl {\n       border: none;\n clear: both;\n  width: 700px;\n}\n\n* .itemLabel {\n    background-color: transparent;\n        margin-left: 0px;\n     width: 140px;\n padding-left: 2px;\n    margin-top: 2px;\n      margin-bottom: 2px;\n   margin-right: 10px;\n   color: gray;\n}\n\n* .entries,* .true-enabledItem-value,* .enabledItem-value, * .disabledItem-value {\n width: 140px;\n padding-left: 2px;\n    border: 1px #74828D solid;\n    background-color: white;\n      margin-top: 2px;\n      margin-bottom: 2px;\n   margin-right: 40px !important;\n        margin-right: 20px;\n} </style>\n<%-- UNCOMMENT AND CLOSE ME AFTER FLAT FORM FOR BASIC STYLE <div class=\"tbpFlatForm\"> --%>\n";

  }

  /**
   * the <code>Appendable</code> to which the config file is written.
   */
  private final transient Appendable appendable;



  /**
   * return the {@link Exception} which occured during the process, or
   * <code>null</code> if the process was a success.
   * 
   * @return exception which occured during process
   */
  public Exception getException()
  {
    return exception;
  }



  /**
   * constructor.
   * 
   * @param formService
   *          the {@link FormService}.
   * @param appendable
   *          the <code>Appendable</code> to which the config file is written
   */
  public JspWriterFormVisitor(final FormService formService, final Appendable appendable)
  {
    this.formService = formService;
    this.appendable = appendable;

    initForm();
  }



  /**
   * init the form writer, insert the jsp directives.
   */
  private void initForm()
  {
    LOGGER.debug(getIndent() + "initForm()");
    try {
      for (String pageDirective : pagesdirectives) {
        append(pageDirective + "\n");
      }

      for (String taglibDirective : taglibdirectives) {
        append(taglibDirective + "\n");
      }
      append(header);
      append("\n" + getIndent() + "");
    }
    catch (final TechnicalIOException e) {
      LOGGER.error(e.getMessage(), e);
    }

  }



  /**
   * append the <code>CharSequence</code> to the <code>Appendable</code>.
   * 
   * @param charSequence
   *          the <code>CharSequence</code> begin appended.
   * @throws TechnicalIOException
   *           if an error occurred
   */
  private void append(final CharSequence charSequence)
      throws TechnicalIOException
  {
    try {
      appendable.append(charSequence);
    }
    catch (final IOException e) {
      throw new TechnicalIOException(e);
    }
  }



  /**
   * append a key message to the result.
   * 
   * @param label
   *          the key
   * @throws TechnicalIOException
   *           if an error occurred
   */
  private void appendKey(GwtI18nMessage label)
      throws TechnicalIOException
  {
    LOGGER.debug(getIndent() + "appendKey()");
    if (label != null) {
      appendStructuralDiv("itemLabel");

      append("\n" + getIndent() + "<fmt:message key='");

      append(label.getKey());

      String[] parameters = label.getParameters();
      if (parameters.length != 0) {
        append("'>");
        for (int i = 0; i < parameters.length; ++i) {

          append("<fmt:param value='");
          append(parameters[i]);
          append("' />");

        }

        append("\n" + getIndent() + "</fmt:message>");

      }
      else {
        append("' />");

      }
      indent--;
      append("\n" + getIndent() + "</div>");

    }
  }



  /**
   * append a div element to the result.
   * 
   * @param id
   *          the id of the div
   * @param classId
   *          the classId of the div
   * @throws TechnicalIOException
   *           if an error occurred
   */
  private void appendIdentifierDiv(String id, String classId)
      throws TechnicalIOException
  {
    LOGGER.debug(getIndent() + "appendIdentifierDiv(" + id + "," + classId + ")");
    if (id != null) {
      append("\n" + getIndent() + "<div id='");
      append(id);
      append("' class='identifierDiv ");
      append(classId);
      append("'>");
      indent++;
    }
    else {
      append("\n" + getIndent() + "<div>");
      indent++;
    }
  }



  /**
   * append a div element to the result.
   * 
   * @param classId
   *          the iclassId of the div
   * @throws TechnicalIOException
   *           if an error occurred
   */
  private void appendStructuralDiv(String classId)
      throws TechnicalIOException
  {
    if (classId != null) {
      LOGGER.debug(getIndent() + "appendStructuralDiv(" + classId + ")");
      append("\n" + getIndent() + "<div class='structuralDiv ");
      append(classId);
      append("'>");
      indent++;
    }
    else {
      append("\n" + getIndent() + "<div>");
      indent++;

    }
  }



  /**
   * return the form's classId.
   * 
   * @param form
   *          the form
   * @return the form's classId
   */
  private String getClassId(Form form)
  {
    if (form != null) {
      return form.getClass().getSimpleName();
    }
    return null;
  }



  /**
   * append the jsp fragment common to all {@link Item}.
   * 
   * @param item
   *          the item being converted
   * @throws TechnicalIOException
   *           if an error occurred
   */
  private void prefixForSimpleItem(final Item item)
      throws TechnicalIOException
  {
    LOGGER.debug(getIndent() + "prefixForSimpleItem(" + item.getName() + ")");
    append("\n" + getIndent() + "<div ");
    append("id='");
    append(item.getName());
    append("'");
    append(" class='simpleItem ");
    append(getClassId(item));
    append("'>");
    indent++;

    if (item.getLabelKey() != null) {
      appendKey(item.getLabelKey());
    }

    String itemDivId = "enabledItem";
    if (!item.isEnabled()) {
      itemDivId = "disabledItem";
    }

    appendStructuralDiv(itemDivId + "-value");

    append("\n" + getIndent() + "<%-- <c:out value=\"${" + getDefaultCOutValueContentFromEntityName(item.getName()) + "}\" /> --%>");
    indent--;
    append("\n" + getIndent() + "</div>");
  }



  /**
   * get the default value from entity name.
   * 
   * @param entityName
   *          the name's entity.
   * @return the default value from entity name.
   */
  private String getDefaultCOutValueContentFromEntityName(String entityName)
  {
    if (entityName != null) {

      String endOfEntityName = entityName.split("-")[entityName.split("-").length - 1];
      String finalEntityName = "";
      int i = 0;
      for (i = 0; i < endOfEntityName.length(); i++) {
        if (endOfEntityName.substring(i, i + 1).toUpperCase().equals(endOfEntityName.substring(i, i + 1))) {
          finalEntityName += ".";
        }
        finalEntityName += endOfEntityName.substring(i, i + 1).toLowerCase();
      }
      return finalEntityName;

    }
    return "";
  }



  /**
   * append the jsp fragment common to all {@link Item}.
   * 
   * @param item
   *          the item being converted
   * @throws TechnicalIOException
   *           if an error occurred
   */
  private void prefixForLabeledItem(final Item item)
      throws TechnicalIOException
  {
    LOGGER.debug(getIndent() + "prefixForLabeledItem(" + item.getName() + ")");
    append("\n" + getIndent() + "<div ");

    append("id='");
    append(item.getName());
    append("'");
    append(" class='labeledItem ");
    append(getClassId(item));
    append("'>");
    indent++;
    if (item.getLabelKey() != null) {
      appendKey(item.getLabelKey());
    }

  }



  /**
   * append the jsp fragment common to all {@link BasicForm}.
   * 
   * @param basicForm
   *          the basic form being generated
   * @throws TechnicalIOException
   *           if an error occurred
   */
  @SuppressWarnings("unchecked")
  private void prefixForBasicForm(BasicForm basicForm)
      throws TechnicalIOException
  {
    LOGGER.debug(getIndent() + "prefixForBasicForm(" + basicForm.getName() + ")");
    appendIdentifierDiv(basicForm.getName(), getClassId(basicForm));
    if (basicForm.getForms() != null && !basicForm.getForms().isEmpty()) {

      for (final Iterator<Form> it = basicForm.getForms().iterator(); it.hasNext();) {
        it.next().accept(this);
      }

    }
    indent--;
    append("\n" + getIndent() + "</div>");

  }



  /**
   * append the jsp fragment common to all {@link BasicForm}.
   * 
   * @param basicForm
   *          the basic form being generated
   * @throws TechnicalIOException
   *           if an error occurred
   */
  @SuppressWarnings("unchecked")
  private void prefixForTabForm(BasicForm basicForm)
      throws TechnicalIOException
  {
    LOGGER.debug(getIndent() + "prefixForBasicForm(" + basicForm.getName() + ")");
    append("\n" + getIndent() + "<div id='tabTitles'>");
    indent++;
    int i = 0;
    for (final Iterator<Form> it = basicForm.getForms().iterator(); it.hasNext();) {

      String name = it.next().getName();
      if (name.contains(".")) {
        // name = name.split(".")[name.split(".").length];
      }
      append("\n" + getIndent() + "<div onclick=\"tabsManager.swapToTab(" + i + ")\" id='tab" + i + "' class='inactiveTab'>" + name + "</div>");
      i++;
    }
    indent--;
    append("\n" + getIndent() + "</div>");

    appendIdentifierDiv("tabs", getClassId(basicForm));

    i = 0;
    if (basicForm.getForms() != null && !basicForm.getForms().isEmpty()) {

      for (final Iterator<Form> it = basicForm.getForms().iterator(); it.hasNext();) {
        append("\n" + getIndent() + "<div class='hiddenTabContent' id='tabContent" + i + "'>");
        indent++;
        it.next().accept(this);
        indent--;
        append("\n" + getIndent() + "</div>");
        i++;
      }

    }

    indent--;
    append("\n" + getIndent() + "</div>");
    append("\n"
        + "<script type=\"text/javascript\">    var tabsCount = "
        + i
        + " ;     var tabsManager = {                     init : function() {                     tabsManager.swapToTab(0);               },              swapToTab : function(tabNumber) {                                                                       for(var i = 0; i < tabsCount; i++){                                     document.getElementById(\"tabContent\" + i).className = \"hiddenTabContent\";                                   if (i == tabNumber)                                     {                                                       document.getElementById(\"tabContent\" + i).className = \"showedTabContent\";                                   }                       }                       for(var i = 0; i < tabsCount; i++){                                     document.getElementById(\"tab\" + i).className = \"inactiveTab\";                                       if (i == tabNumber)                                     {                                                       document.getElementById(\"tab\" + i).className = \"activeTab\";                                 }                       }               }       };      tabsManager.init();</script>");

  }



  /**
   * append the jsp fragment common to all <code>ValuedItem</code>.
   * 
   * @param item
   *          the item being converted
   * @throws TechnicalIOException
   *           if an error occurred
   */
  private void prefixForValuedItem(final ValuedItem item)
      throws TechnicalIOException
  {
    LOGGER.debug(getIndent() + "prefixForValuedItem(" + item.getName() + ")");
    prefixForLabeledItem(item);

    if (item.getEntries() != null) {
      append("\n" + getIndent() + "<div class='entries'>");
      indent++;
      item.getEntries().accept(this);
      indent--;
      append("\n" + getIndent() + "</div>");
    }
    indent--;
    append("\n" + getIndent() + "</div>");

  }



  /**
   * generate checkBoxItem from a CheckBox widget.
   * 
   * @param item
   *          an object CheckBoxItem.
   * @throws TechnicalIOException
   */
  public void visitCheckBoxItem(final CheckBoxItem item)
  {
    LOGGER.debug(getIndent() + "visitCheckBoxItem(" + item.getName() + ")");
    if (exception != null) {
      return;
    }
    try {

      appendIdentifierDiv(item.getName(), getClassId(item));

      String itemDivId = "enabledItem";
      if (!item.isEnabled()) {
        itemDivId = "disabledItem";
      }

      appendStructuralDiv(itemDivId + "-value checkboxItemContainer");
      append("\n" + getIndent() + "<input <%-- <c:if test=\"${" + getDefaultCOutValueContentFromEntityName(item.getName())
          + " == true}\"> checked=\"checked\" </c:if> --%> class=\"checkbox\" type=\"checkbox\" name=\"" + item.getName() + "\" disabled=\"disabled\"" + "/>");
      indent--;
      append("\n" + getIndent() + "</div>");

      if (item.getLabelKey() != null) {
        appendKey(item.getLabelKey());
      }
      indent--;
      append("\n" + getIndent() + "</div>");
    }
    catch (TechnicalIOException tioe) {
      exception = tioe;
    }

  }



  /**
   * create a new widget from a groupForm.
   * 
   * @param horizontalForm
   *          is of type GroupForm. contains a list of Forms.
   */

  public void visitHorizontalForm(final HorizontalForm horizontalForm)
  {
    LOGGER.debug(getIndent() + "visitHorizontalForm(" + horizontalForm.getName() + ")");
    if (exception != null) {
      return;
    }
    try {
      prefixForBasicForm(horizontalForm);
    }
    catch (TechnicalIOException tioe) {
      exception = tioe;
    }

  }



  /**
   * this method implement ImageItem from widget Image'gwt.
   * 
   * @param imageItem
   *          is of type ImageItem.
   */
  public void visitImageItem(final ImageItem imageItem)
  {
    LOGGER.debug(getIndent() + "visitImageItem(" + imageItem.getName() + ")");
    if (exception != null) {
      return;
    }

    try {
      prefixForSimpleItem(imageItem);
      appendImageItem(imageItem);
      indent--;
      append("\n" + getIndent() + "</div>");

    }
    catch (TechnicalIOException tioe) {
      exception = tioe;
    }

  }



  /**
   * append the image html fragment for <code>ImageItem</code>.
   * 
   * @param imageItem
   *          the item being converted
   * @throws TechnicalIOException
   *           if an error occurred
   */
  private void appendImageItem(final ImageItem imageItem)
      throws TechnicalIOException
  {
    LOGGER.debug(getIndent() + "appendImageItem(" + imageItem.getName() + ")");
    if (imageItem != null) {
      append("\n" + getIndent() + "<img class=\"imageItem\" src=\"");
      append(imageItem.getUrl());
      append("\" />");
    }
  }



  /**
   * visit a {@link ListBoxItem}.
   * 
   * @param listBoxItem
   *          is a listbox.
   */
  public void visitListBoxItem(final ListBoxItem listBoxItem)
  {
    LOGGER.debug(getIndent() + "visitListBoxItem(" + listBoxItem.getName() + ")");
    if (exception != null) {
      return;
    }

    try {
      prefixForSimpleItem(listBoxItem);

      indent--;
      append("\n" + getIndent() + "</div>");
    }
    catch (TechnicalIOException tioe) {
      exception = tioe;
    }

  }



  /**
   * Generate RadioButtonItem from RadioButton widget.
   * 
   * @param radioButtonItem
   *          is of type RadioButton.
   */
  public void visitRadioButtonItem(final RadioButtonItem radioButtonItem)
  {
    LOGGER.debug(getIndent() + "visitRadioButtonItem(" + radioButtonItem.getName() + ")");
    if (exception != null) {
      return;
    }

    try {
      parentItem = radioButtonItem;
      prefixForValuedItem(radioButtonItem);

    }
    catch (TechnicalIOException tioe) {
      exception = tioe;
    }
  }



  /**
   * visit {@link SubFormMultipleItem}.
   * 
   * @param item
   *          the item to visit
   * @throws GwtBundledException
   */
  public void visitSubFormMultipleItem(SubFormMultipleItem item)
  {
    LOGGER.debug(getIndent() + "visitSubFormMultipleItem(" + item.getName() + ")");
    if (exception != null) {
      return;
    }
    try {
      /*
       * TODO CHANGE WITH DataIdentifier
       */
      if (item.getSubFormIdentifier() != null) {
        if (item.getSubFormIdentifier().toString().length() > 1) {
          appendIdentifierDiv(item.getName(), getClassId(item));
          append("\n" + getIndent() + "<div class='structuralDiv itemLabel'>");
          indent++;
          append("\n" + getIndent() + "<fmt:message key='" + item.getLabelKey().getKey() + "' />");
          indent--;
          append("\n" + getIndent() + "</div>");
          indent--;
          append("\n" + getIndent() + "</div>");
        }
      }
    }
    catch (Exception tioe) {
      tioe.printStackTrace();
      exception = tioe;
    }

  }



  /**
   * visit {@link SubFormSimpleItem}.
   * 
   * @param item
   *          the item to visit
   */
  public void visitSubFormSimpleItem(final SubFormSimpleItem item)
  {
    LOGGER.debug(getIndent() + "visitSubFormSimpleItem(" + item.getName() + ")");
    if (exception != null) {
      return;
    }
    try {
      /*
       * TODO CHANGE WITH DataIdentifier
       */
      if (item.getSubFormIdentifier() != null) {
        if (item.getSubFormIdentifier().toString().length() > 1) {
          appendIdentifierDiv(item.getName(), getClassId(item));
          append("\n" + getIndent() + "<div class='structuralDiv itemLabel'>");
          indent++;
          append("\n" + getIndent() + "<fmt:message key='" + item.getLabelKey().getKey() + "' />");
          indent--;
          append("\n" + getIndent() + "</div>");

          append("\n" + getIndent() + "<div class='structuralDiv enabledItem-value'>");
          indent++;
          append("\n" + getIndent() + "<%-- put value here --%>");
          indent--;
          append("\n" + getIndent() + "</div>");

          indent--;
          append("\n" + getIndent() + "</div>");
        }
      }
    }
    catch (Exception tioe) {
      tioe.printStackTrace();
      exception = tioe;
    }

  }



  /**
   * create a form from tabForm.
   * 
   * @param tabForm
   *          is of type TabForm.He is composed of Forms.
   */
  public void visitTabForm(final TabForm tabForm)
  {
    LOGGER.debug("visitTabForm(" + tabForm.getName() + ")");
    if (exception != null) {
      return;
    }
    try {
      prefixForTabForm(tabForm);
    }
    catch (TechnicalIOException tioe) {
      exception = tioe;
    }

  }



  /**
   * this method implement ImageItem from widget Image'gwt.
   * 
   * @param labelItem
   *          is of type LabelItem.
   */
  public void visitLabelItem(final LabelItem labelItem)
  {
    LOGGER.debug(getIndent() + "visitLabelItem(" + labelItem.getName() + ")");
    visitSimpleItem(labelItem);
    parentItem = labelItem;
  }



  /**
   * visit a {@link ButtonItem}.
   * 
   * @param buttonItem
   *          the {@link ButtonItem} to visit
   */
  public void visitButtonItem(ButtonItem buttonItem)
  {
    // TODO visitButtonItem.
  }



  /**
   * Generate a PasswordBoxItem from a PasswordBox widget.
   * 
   * @param passwordBoxItem
   *          is of type passwordBox.
   */
  public void visitPasswordBoxItem(final PasswordBoxItem passwordBoxItem)
  {
    LOGGER.debug(getIndent() + "visitPasswordBoxItem(" + passwordBoxItem.getName() + ")");
    visitSimpleItem(passwordBoxItem);
    parentItem = passwordBoxItem;
  }



  /**
   * Generate a TextAreaItem from a TextArea widget.
   * 
   * @param textAreaItem
   *          is of type TextArea.
   */
  public void visitTextAreaItem(final TextAreaItem textAreaItem)
  {
    LOGGER.debug(getIndent() + "visitTextAreaItem(" + textAreaItem.getName() + ")");
    visitSimpleItem(textAreaItem);
    parentItem = textAreaItem;
  }



  /**
   * this method implement a RichTextAreaItem with RichTextArea from gwt.
   * 
   * @param richTextAreaItem
   *          an item.
   */
  public void visitRichTextAreaItem(final RichTextAreaItem richTextAreaItem)
  {
    LOGGER.debug(getIndent() + "visitRichTextAreaItem(" + richTextAreaItem.getName() + ")");
    visitSimpleItem(richTextAreaItem);
    parentItem = richTextAreaItem;
  }



  /**
   * handling {@link SimpleItem} with no other properties.
   * 
   * @param simpleItem
   *          the {@link SimpleItem} to display
   */
  private void visitSimpleItem(SimpleItem simpleItem)
  {
    LOGGER.debug(getIndent() + "visitSimpleItem(" + simpleItem.getName() + ")");
    if (exception != null) {
      return;
    }

    try {
      prefixForSimpleItem(simpleItem);
      indent--;
      append("\n" + getIndent() + "</div>");
    }
    catch (TechnicalIOException tioe) {
      exception = tioe;
    }

  }



  /**
   * generate textBoxItem from a textbox widget.
   * 
   * @param textBoxItem
   *          is of type TextBoxItem.
   */
  public void visitTextBoxItem(final TextBoxItem textBoxItem)
  {
    LOGGER.debug(getIndent() + "visitTextBoxItem(" + textBoxItem.getName() + ")");
    visitSimpleItem(textBoxItem);
    parentItem = textBoxItem;
  }



  /**
   * generate dateItem from a textbox widget.
   * 
   * @param dateItem
   *          is of type {@link DateItem}.
   */
  public void visitDateItem(DateItem dateItem)
  {
    LOGGER.debug(getIndent() + "visitDateItem(" + dateItem.getName() + ")");
    visitSimpleItem(dateItem);
    parentItem = dateItem;
  }



  /**
   * generate timeItem from a textbox widget.
   * 
   * @param timeItem
   *          is of type {@link TimeItem}.
   */
  public void visitTimeItem(TimeItem timeItem)
  {
    LOGGER.debug(getIndent() + "visitTimeItem(" + timeItem.getName() + ")");
    visitSimpleItem(timeItem);
    parentItem = timeItem;
  }



  /**
   * generate dateTimeItem from a textbox widget.
   * 
   * @param dateTimeItem
   *          is of type {@link DateTimeItem}.
   */
  public void visitDateTimeItem(DateTimeItem dateTimeItem)
  {
    LOGGER.debug(getIndent() + "visitDateTimeItem(" + dateTimeItem.getName() + ")");
    visitSimpleItem(dateTimeItem);
    parentItem = dateTimeItem;
  }



  /**
   * visit {@link FileUploadItem}.
   * 
   * @param item
   *          the item to visit
   * @see com.genia.toolbox.web.gwt.form.client.visitor.FormVisitor#visitFileUploadItem(com.genia.toolbox.web.gwt.form.client.form.impl.FileUploadItemImpl)
   */
  public void visitFileUploadItem(FileUploadItem item)
  {
    LOGGER.debug(getIndent() + "visitFileUploadItem(" + item.getName() + ")");
    visitSimpleItem(item);
    parentItem = item;

  }



  /**
   * visit {@link MultipleFileUploadItem}.
   * 
   * @param item
   *          the item to visit
   * @see com.genia.toolbox.web.gwt.form.client.visitor.FormVisitor#visitFileUploadItem(com.genia.toolbox.web.gwt.form.client.form.impl.FileUploadItemImpl)
   */
  public void visitMultipleFileUploadItem(MultipleFileUploadItem item)
  {
    LOGGER.debug(getIndent() + "visitMultipleFileUploadItem(" + item.getName() + ")");
    visitSimpleItem(item);
    parentItem = item;
  }



  /**
   * visit {@link VerticalForm}.
   * 
   * @param item
   *          the item to visit
   * @see {@link com.genia.toolbox.web.gwt.form.client.visitor.FormVisitor#visitVerticalForm(VerticalForm)}
   */
  public void visitVerticalForm(VerticalForm item)
  {
    LOGGER.debug(getIndent() + "visitVerticalForm(" + item.getName() + ")");
    if (exception != null) {
      return;
    }
    try {
      prefixForBasicForm(item);
    }
    catch (TechnicalIOException tioe) {
      exception = tioe;
    }

  }



  /**
   * visit {@link EnumDescriptableValuedItemEntryList}.
   * 
   * @param valuedItemEntryList
   *          to visit
   */
  public void visitEnumDescriptableValuedItemEntryList(EnumDescriptableValuedItemEntryList valuedItemEntryList)
  {
    LOGGER.debug(getIndent() + "visitEnumDescriptableValuedItemEntryList(" + parentItem.getName() + ")");
    visitValuedItemEntryList(valuedItemEntryList);
  }



  /**
   * visit {@link SimpleValuedItemEntryList}.
   * 
   * @param valuedItemEntryList
   *          to visit
   */
  public void visitSimpleValuedItemEntryList(SimpleValuedItemEntryList valuedItemEntryList)
  {
    LOGGER.debug(getIndent() + "visitSimpleValuedItemEntryList(" + parentItem.getName() + ")");
    visitValuedItemEntryList(valuedItemEntryList);
  }



  /**
   * visit {@link SimpleValuedItemEntryList}.
   * 
   * @param valuedItemEntryList
   *          to visit
   */
  @SuppressWarnings("unchecked")
  private void visitValuedItemEntryList(ValuedItemEntryList valuedItemEntryList)
  {
    LOGGER.debug(getIndent() + "visitValuedItemEntryList(" + parentItem.getName() + ")");
    if (exception != null) {
      return;
    }
    try {
      if (valuedItemEntryList.getValuedItemEntries() != null && !valuedItemEntryList.getValuedItemEntries().isEmpty()) {
        String parentItemObject = parentItem.getName();
        appendValuedItemEntryList(parentItem, parentItemObject, valuedItemEntryList.getValuedItemEntries());
      }

    }
    catch (TechnicalIOException tioe) {
      exception = tioe;
    }

  }



  /**
   * append a valued item list for the parent item.
   * 
   * @param parentItem
   *          the parent item.
   * @param name
   *          the name of the list.
   * @param valuedItemEntries
   *          the list of valued item.
   * @throws TechnicalIOException
   *           if an error occurred
   */
  private void appendValuedItemEntryList(Form parentItem, String name, List<ValuedItemEntry> valuedItemEntries)
      throws TechnicalIOException
  {
    LOGGER.debug(getIndent() + "appendValuedItemEntryList(" + name + ")");

    if (parentItem == null) {
      throw new IllegalArgumentException("parentItem is null");
    }

    if (name == null) {
      throw new IllegalArgumentException("name is null");
    }

    if (valuedItemEntries == null) {
      throw new IllegalArgumentException("valuedItemEntries is null");
    }

    if (parentItem instanceof RadioButtonItem) {
      append("\n" + getIndent() + "<%-- <fmt:message key=\"${" + getDefaultCOutValueContentFromEntityName(name) + ".description.key}\"/> --%>\n");
    }
    else if (parentItem instanceof ListBoxItem) {

      String multipleSelect = "";

      if (((ListBoxItem) parentItem).isMultipleSelect()) {
        multipleSelect = "multiple='multiple'";
      }
      String size = "size='" + ((ListBoxItem) parentItem).getVisibleItemCount() + "'";
      append("\n" + getIndent() + "<select class=\"listBox\" name='" + name + "' " + multipleSelect + " " + size + " readonly=\"readonly\">");
      indent++;
      for (ValuedItemEntry entry : valuedItemEntries) {
        /* TODO Loop on results to select or not each option */
        append("\n" + getIndent() + "<option value=\"" + entry.getValue() + "\">");
        if (entry.getLabel() != null) {
          appendKey(entry.getLabel());
        }
        append("\n" + getIndent() + "</option>");

      }
      indent--;
      append("\n" + getIndent() + "</select>");
    }

  }



  /**
   * visit a {@link LabeledForm}.
   * 
   * @param labeledForm
   *          the {@link LabeledForm} to visit
   */
  public void visitLabeledForm(LabeledForm labeledForm)
  {
    LOGGER.debug(getIndent() + "visitLabeledForm(" + labeledForm.getName() + ")");
    if (exception != null) {
      return;
    }

    try {
      appendIdentifierDiv(labeledForm.getName(), getClassId(labeledForm));
      if (labeledForm.getSubForm() != null) {
        labeledForm.getSubForm().accept(this);
      }
      indent--;
      append("\n" + getIndent() + "</div>");

    }
    catch (TechnicalIOException tioe) {
      exception = tioe;
    }

  }



  /**
   * visit a {@link I18nTextAreaItem}.
   * 
   * @param i18nTextAreaItem
   *          the {@link I18nTextAreaItem} to visit
   */
  public void visitI18nTextAreaItem(final I18nTextAreaItem i18nTextAreaItem)
  {
    LOGGER.debug(getIndent() + "visitI18nTextAreaItem(" + i18nTextAreaItem.getName() + ")");
    visitSimpleItem(i18nTextAreaItem);
    parentItem = i18nTextAreaItem;
  }



  /**
   * visit a {@link I18nTextBoxItem}.
   * 
   * @param item
   *          the {@link I18nTextBoxItem} to visit
   */
  public void visitI18nTextBoxItem(I18nTextBoxItem item)
  {
    LOGGER.debug(getIndent() + "visitI18nTextBoxItem(" + item.getName() + ")");
    visitSimpleItem(item);
    parentItem = item;
  }



  /**
   * visit a {@link InlineFormMultipleItem}.
   * 
   * @param inlineFormMultipleItem
   *          the {@link InlineFormMultipleItem} to visit
   */
  public void visitInlineFormMultipleItem(InlineFormMultipleItem inlineFormMultipleItem)
  {
    LOGGER.debug(getIndent() + "visitInlineFormMultipleItem(" + inlineFormMultipleItem.getName() + ")");
    if (exception != null) {
      return;
    }

    try {
      prefixForInlineFormItem(inlineFormMultipleItem);
      Form subForm = getFormService().getForm(inlineFormMultipleItem.getInlineFormIdentifier(), new DataIdentifierImpl());
      subForm.accept(this);
    }
    catch (TechnicalIOException tioe) {
      exception = tioe;
    }
    catch (GwtBundledException e) {

    }

  }



  /**
   * append the prefix jsp fragment common to all <code>InlineFormItem</code>.
   * 
   * @param inlineFormItem
   *          the item being converted
   * @throws TechnicalIOException
   *           if an error occurred
   */
  private void prefixForInlineFormItem(final InlineFormItem inlineFormItem)
      throws TechnicalIOException
  {
    LOGGER.debug(getIndent() + "prefixForInlineFormItem(" + inlineFormItem.getName() + ")");
    prefixForSimpleItem(inlineFormItem);
    indent--;
    append("\n" + getIndent() + "</div>");
  }



  /**
   * visit a {@link DynamicRadioButtonItem}.
   * 
   * @param item
   *          the {@link DynamicRadioButtonItem} to visit
   */
  public void visitDynamicRadioButtonItem(DynamicRadioButtonItem item)
  {
    LOGGER.debug(getIndent() + "visitDynamicRadioButtonItem(" + item.getName() + ")");
    visitSimpleItem(item);
    // append("\n" + getIndent() + "<% // TODO this item is a dynamic list of
    // value, you must enter
    // the right value yourself %>\n");
    parentItem = item;
  }



  /**
   * visit a {@link DynamicListBoxItem}.
   * 
   * @param item
   *          the {@link DynamicListBoxItem} to visit
   */
  public void visitDynamicListBoxItem(DynamicListBoxItem item)
  {
    LOGGER.debug(getIndent() + "visitDynamicListBoxItem(" + item.getName() + ")");
    try {
      visitSimpleItem(item);
      append("\n" + getIndent() + "<%-- <fmt:message key=\"${" + getDefaultCOutValueContentFromEntityName(item.getName()) + ".name.key}\" /> --%>\n");
      parentItem = item;
    }
    catch (TechnicalIOException tioe) {
      exception = tioe;
    }
  }



  /**
   * visit a {@link InlineFormSimpleItem}.
   * 
   * @param inlineFormSimpleItem
   *          the {@link InlineFormSimpleItem} to visit
   */
  public void visitInlineFormSimpleItem(InlineFormSimpleItem inlineFormSimpleItem)
  {
    LOGGER.debug(getIndent() + "visitInlineFormSimpleItem(" + inlineFormSimpleItem.getName() + ")");
    if (exception != null) {
      return;
    }

    try {
      prefixForInlineFormItem(inlineFormSimpleItem);
      Form subForm = getFormService().getForm(inlineFormSimpleItem.getInlineFormIdentifier(), new DataIdentifierImpl());
      subForm.accept(this);
    }
    catch (TechnicalIOException tioe) {
      exception = tioe;
    }
    catch (GwtBundledException e) {

    }
  }



  /**
   * getter for the formService property.
   * 
   * @return the formService
   */
  public FormService getFormService()
  {
    return formService;
  }



  /**
   * return indent.
   * 
   * @return indent.
   */
  private String getIndent()
  {

    String ret = "";
    for (int i = 0; i < indent; i++) {
      ret += "    ";

    }
    return ret;

  }

}
